package com.example.springbootshiro.shiro.filter;

import com.alibaba.fastjson.JSON;
import com.example.springbootshiro.response.BusinessError;
import com.example.springbootshiro.response.CommonReturnData;
import com.example.springbootshiro.response.GlobalCodeEnum;
import com.example.springbootshiro.service.PermissionService;
import com.example.springbootshiro.shiro.token.TokenObject;
import com.example.springbootshiro.util.ApplicationContextUtil;
import com.example.springbootshiro.util.JwtUtil;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.Writer;

/**
 * 自定义认证过滤器：
 * 1，手动身份认证
 * 2，手动权限认证
 * <p>
 * Created by YangGang on 2021/12/15 17:11。
 */
@Slf4j
public class MyAuthenticatingFilter extends BasicHttpAuthenticationFilter {
    private String authentication = "Authentication";

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        log.debug("");
        log.debug("----- MyAuthenticatingFilter ----");
        log.debug("-------------- start ------------");
        if (((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())) {
            return true;
        }
        Subject subject = getSubject(request, response);
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String headerToken = httpServletRequest.getHeader(authentication);
        log.debug("Header中拿到的Token：" + headerToken);
        if (StringUtils.isEmpty(headerToken)) {
            responseError(response, GlobalCodeEnum.NO_LOGIN);//未登陆
            return false;
        }
        //解析headerToken得到需要的数据
        TokenObject userToken = null;
        try {
            userToken = JwtUtil.parsing(headerToken, TokenObject.class);
        } catch (ExpiredJwtException e) {
            responseError(response, GlobalCodeEnum.TOKEN_EXPIRED);//token已过期
            return false;
        } catch (Exception e) {
            responseError(response, GlobalCodeEnum.TOKEN_INVALID);//token未成功解析时,即token异常
            return false;
        }
        //转成 AuthenticationToken 执行登陆
        try {
            AuthenticationToken token = new UsernamePasswordToken(userToken.getUsername(), userToken.getPassword());
            subject.login(token);
        } catch (UnknownAccountException e) {
            responseError(response, GlobalCodeEnum.NOT_FIND_USER);//用户不存在
            return false;
        } catch (IncorrectCredentialsException e) {
            responseError(response, GlobalCodeEnum.LOGIN_CHECK_ERROR);//用户名或密码错误
            return false;
        } catch (BusinessError e) {
            responseError(response, e.getGlobalCodeEnum());//抛的业务异常
            return false;
        } catch (Exception e) {
            //未知异常：认证异常，请稍后再试
            e.printStackTrace();
            GlobalCodeEnum codeEnum = GlobalCodeEnum.DEFAULT_ERROR;
            codeEnum.setMessage(e.getMessage());
            responseError(response, codeEnum);
            return false;
        }
        //验证用户是否有权限
        String servletPath = ((HttpServletRequest) request).getServletPath();
        PermissionService permissionService = ApplicationContextUtil.getBeanByClass(PermissionService.class);
        String permissionTag = permissionService.findPermissionMapCache().get(servletPath);
        if (!ObjectUtils.isEmpty(permissionTag)) {
            if (!subject.isPermitted(permissionTag)) {//查看是否有权限
                responseError(response, GlobalCodeEnum.NOT_PERMISSION);//没有权限
                return false;
            }
        }

        log.debug("-------------- end ------------");
        log.debug("----- MyAuthenticatingFilter ----");
        return true;
    }


    private void responseError(ServletResponse response, GlobalCodeEnum globalCodeEnum) {
        log.debug("自定义认证过滤器在认证时出现异常:" + globalCodeEnum.getMessage());
        Writer writer = null;
        try {
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            String result = JSON.toJSONString(CommonReturnData.create(null, globalCodeEnum));
            writer = response.getWriter();
            writer.write(result);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


}
